package com.lemon.cloud.admin.web;

import com.alicp.jetcache.anno.CacheInvalidate;
import com.alicp.jetcache.anno.CachePenetrationProtect;
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.anno.Cached;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lemon.cloud.admin.entity.SysDict;
import com.lemon.cloud.admin.entity.SysDictItem;
import com.lemon.cloud.admin.service.SysDictItemService;
import com.lemon.cloud.admin.service.SysDictService;
import com.lemon.cloud.comm.constants.CacheConstants;
import com.lemon.cloud.comm.constants.enums.LogBusType;
import com.lemon.cloud.comm.model.ResultMsg;
import com.lemon.cloud.log.annotation.SysLog;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.StringUtils;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;
import java.util.List;

@RestController
@RequestMapping("dict")
@Tag(name = "字典接口")
public class SysDictController {

    @Autowired
    private SysDictService dictService;

    @Autowired
    private SysDictItemService dictItemService;

    @Operation(
            summary = "分页查询",description = "分页查询字典信息",
            responses = {
                    @ApiResponse(responseCode = "200",description = "successful operation",content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE,schema = @Schema(implementation = IPage.class))},useReturnTypeSchema = true)
            }
    )
    @GetMapping("/page")
    public ResultMsg<IPage<SysDict>> page(@ParameterObject Page<SysDict> page,
                                          @ParameterObject SysDict dict){
        return ResultMsg.resultSuccess(dictService.page(page, Wrappers.<SysDict>query().lambda()
                .eq(StringUtils.isNotEmpty(dict.getSystemFlag()),SysDict::getSystemFlag,dict.getSystemFlag())
                .like(StringUtils.isNotEmpty(dict.getType()),SysDict::getType,dict.getType()))
        );
    }

    /**
     * 通过字典类型查找字典
     * @param type 类型
     * @return 同类型字典
     */
    @Operation(
            summary = "通过字典类型查找字典",description = "通过字典类型查找字典",
            parameters = {@Parameter(description = "字典类型",in = ParameterIn.PATH,name = "type")},
            responses = {
                    @ApiResponse(responseCode = "200",description = "successful operation",content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE,schema = @Schema(implementation = List.class))},useReturnTypeSchema = true)
            }
    )
    @GetMapping("/type/{type}")
    @Cached(name = CacheConstants.DICT_DETAILS, key = "#type",expire = 3600,cacheType = CacheType.BOTH)
    @CachePenetrationProtect
    public ResultMsg<List<SysDictItem>> getDictByType(@PathVariable("type") String type) {
        return ResultMsg.resultSuccess(dictItemService.list(Wrappers.<SysDictItem>query().lambda().eq(SysDictItem::getType, type)));
    }

    /**
     * 修改字典
     * @param dict
     * @return
     */
    @Operation(
            summary = "修改字典",
            responses = {
                    @ApiResponse(responseCode = "200",description = "successful operation",content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE,schema = @Schema(implementation = Boolean.class))},useReturnTypeSchema = true),
                    @ApiResponse(responseCode = "400", description = "无效参数")
            }
    )
    @SysLog(value = "修改字典",businessType = LogBusType.MODIFY)
    @PutMapping
    @PreAuthorize("hasAnyAuthority('sys_dict_edit')")
    public ResultMsg<Boolean> updateSysDict(@Parameter @Valid @RequestBody SysDict dict){
        if (dict.getId()==null){
            return ResultMsg.resultFail("id不能为空");
        }
        return ResultMsg.resultSuccess(dictService.updateById(dict));
    }

    /**
     * 删除
     * @param id
     * @return
     */
    @Operation(
            summary = "删除字典",
            parameters = {@Parameter(description = "id",in = ParameterIn.PATH,name = "id",required = true)},
            responses = {
                    @ApiResponse(responseCode = "200",description = "successful operation",content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE,schema = @Schema(implementation = Boolean.class))},useReturnTypeSchema = true),
                    @ApiResponse(responseCode = "400", description = "无效参数")
            }
    )
    @PreAuthorize("hasAnyAuthority('sys_dict_del')")
    @SysLog(value = "删除字典",businessType = LogBusType.DELETE)
    @DeleteMapping("{id:\\d+}")
    public ResultMsg<Boolean> delSysDict(@PathVariable("id") Long id){
        return ResultMsg.resultSuccess(dictService.removeById(id));
    }

    /**
     * 新增
     * @param sysDict
     * @return
     */
    @Operation(
            summary = "新增字典",
            responses = {
                    @ApiResponse(responseCode = "200",description = "successful operation",content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE,schema = @Schema(implementation = SysDict.class))},useReturnTypeSchema = true),
                    @ApiResponse(responseCode = "400", description = "无效参数")
            }
    )
    @SysLog(value = "新增字典",businessType = LogBusType.ADD)
    @PostMapping
    @PreAuthorize("hasAnyAuthority('sys_dict_add')")
    public ResultMsg<SysDict> addSysDict(@Parameter @Valid @RequestBody SysDict sysDict){
        dictService.save(sysDict);
        return ResultMsg.resultSuccess(sysDict);
    }

    /**
     * 分页查询字典项
     */
    @Operation(
            summary = "分页查询字典项",
            responses = {
                    @ApiResponse(responseCode = "200",description = "successful operation",content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE,schema = @Schema(implementation = IPage.class))},useReturnTypeSchema = true),
                    @ApiResponse(responseCode = "400", description = "无效参数")
            }
    )
    @GetMapping("/item/page")
    public ResultMsg<IPage<SysDictItem>> itemPage(@ParameterObject Page<SysDictItem> page,
                                                  @ParameterObject SysDictItem dictItem){
        return ResultMsg.resultSuccess(dictItemService.page(page,Wrappers.query(dictItem)));
    }

    /**
     * 新增字典项
     * @param dictItem
     * @return
     */
    @Operation(
            summary = "新增字典项",
            responses = {
                    @ApiResponse(responseCode = "200",description = "successful operation"),
                    @ApiResponse(responseCode = "400", description = "无效参数")
            }
    )
    @SysLog(value = "新增字典项",businessType = LogBusType.ADD)
    @PostMapping("item")
    @CacheInvalidate(name = CacheConstants.DICT_DETAILS, key = "#dictItem.type")
    @PreAuthorize("hasAnyAuthority('sys_dict_add')")
    public ResultMsg<Boolean> addSysDictItem(@Parameter @Valid @RequestBody SysDictItem dictItem){
        validDictItem(dictItem);
        return ResultMsg.resultSuccess(dictItemService.save(dictItem));
    }

    /**
     * 修改字典项
     * @param dictItem
     * @return
     */
    @Operation(
            summary = "修改字典项",
            responses = {
                    @ApiResponse(responseCode = "200",description = "successful operation"),
                    @ApiResponse(responseCode = "400", description = "无效参数")
            }
    )
    @SysLog(value = "修改字典项",businessType = LogBusType.MODIFY)
    @PutMapping("item")
    @CacheInvalidate(name = CacheConstants.DICT_DETAILS, key = "#dictItem.type")
    @PreAuthorize("hasAnyAuthority('sys_dict_edit')")
    public ResultMsg<Boolean> updateSysDictItem(@Parameter @Valid @RequestBody SysDictItem dictItem){
        if (dictItem.getId()==null){
            return ResultMsg.resultFail("id不能为空");
        }
        validDictItem(dictItem);
        return ResultMsg.resultSuccess(dictItemService.updateById(dictItem));
    }

    /**
     * 删除字典项
     * @param id
     * @return
     */
    @Operation(
            summary = "修改字典项",
            parameters = {@Parameter(name = "id",required = true,in = ParameterIn.PATH,description = "id")},
            responses = {
                    @ApiResponse(responseCode = "200",description = "successful operation"),
                    @ApiResponse(responseCode = "400", description = "无效参数")
            }
    )
    @SysLog(value = "删除字典项",businessType = LogBusType.DELETE)
    @DeleteMapping("/item/{id}")
    @PreAuthorize("hasAnyAuthority('sys_dict_del')")
    public ResultMsg<Boolean> delSysDictItem(@PathVariable("id") Long id){
        return ResultMsg.resultSuccess(dictItemService.delSysDictItem(dictItemService.getById(id)));
    }

    /**
     * 清除字典缓存
     * @return
     */
    @Operation(
            summary = "清除字典缓存",
            responses = {
                    @ApiResponse(responseCode = "200",description = "successful operation")
            }
    )
    @SysLog(value = "清除字典缓存",businessType = LogBusType.DELETE)
    @DeleteMapping("/cache")
    @CacheInvalidate(name = CacheConstants.DICT_DETAILS,key = "#type")
    @PreAuthorize("hasAnyAuthority('sys_dict_del')")
    public ResultMsg<Boolean> clearDictCache() {
        return ResultMsg.resultSuccess();
    }

    /**
     * 校验字典项
     * @return
     */
    public void validDictItem(SysDictItem dictItem){
        long count = dictItemService.count(new LambdaQueryWrapper<SysDictItem>()
                .and(w-> w.eq(SysDictItem::getValue, dictItem.getValue())
                            .or()
                            .eq(SysDictItem::getLabel, dictItem.getLabel()))
                .eq(SysDictItem::getDictId, dictItem.getDictId())
                .ne(dictItem.getId() != null, SysDictItem::getId, dictItem.getId())
        );
        Assert.state(count==0,"字典类型"+dictItem.getType()+",存在相同的标签或者值");
    }


}

